#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <unistd.h>  
#include <arpa/inet.h>       
#include <time.h>
#include <fcntl.h>

#include "tcp_server.h"
#include "process.h"
#include "database.h"


int init_tcp_server(struct sockaddr_in *addr_local, struct sockaddr_in *addr_remote)
{
	int sockfd = 0; 					   // Socket file descriptor
	struct linger so_linger;
	
	/* Get the Socket file descriptor */  
	if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )  
	{   
		printf ("ERROR: Failed to obtain Socket Despcritor.\n");
		return (0);
	} else 
	{
		printf ("OK: Obtain Socket Despcritor sucessfully.\n");
	}

	/* Fill the local socket address struct */
	addr_local->sin_family = AF_INET;           			// Protocol Family
	addr_local->sin_port = htons (PORT);         		// Port number
	addr_local->sin_addr.s_addr  = htonl (INADDR_ANY);	// AutoFill local address
	memset (addr_local->sin_zero,0,8);          			// Flush the rest of struct

	/*  Blind a special Port */
	if( bind(sockfd, (struct sockaddr*)addr_local, sizeof(struct sockaddr)) == -1 )
	{  
		printf ("ERROR: Failed to bind Port %d.\n",PORT);
		return (0);
	} else {
		printf("OK: Bind the Port %d sucessfully.\n",PORT);
	}

	/*  Listen remote connect/calling */
	if(listen(sockfd,BACKLOG) == -1)    
	{  
		printf ("ERROR: Failed to listen Port %d.\n", PORT);
		return (0);
	} else 
	{
		printf ("OK: Listening the Port %d sucessfully.\n", PORT);
	}
	
	so_linger.l_onoff  = 1;
	so_linger.l_linger = 0;
	setsockopt(sockfd,SOL_SOCKET,SO_LINGER,&so_linger,sizeof(so_linger));

	return sockfd;

}

int tcp_server (int argc, char *argv[])
{  
	int sockfd;
	int nsockfd;               		// New Socket file descriptor

	int sin_size;                      	// to store struct size
	int fork_id = 0, pr = 0;
	
	struct sockaddr_in addr_local; 
	struct sockaddr_in addr_remote;

	//init socket tcp server
	sockfd = init_tcp_server(&addr_local,&addr_remote);
	if(0 == sockfd)
	{
		return 0;
	}
	
	while(1)
	{  
		//printf ("Wait a new connection.\n");
		sin_size = sizeof(struct sockaddr_in);  

		/*  Wait a connection, and obtain a new socket file despriptor for single connection */
		if ((nsockfd = accept(sockfd, (struct sockaddr *)&addr_remote, (socklen_t *__restrict)&sin_size)) == -1)
		{  
			//printf ("ERROR: Obtain new Socket Despcritor error.\n");
#ifdef DATABASE			
			/*insert db*/
			insert_db_bus_connect(inet_ntoa(addr_remote.sin_addr));
#endif
			continue;
		} 
		else 
		{
#ifdef DATABASE			
			insert_db_bus_connect(inet_ntoa(addr_remote.sin_addr));
#endif
			printf ("OK: Server has got connect from %s.\n", inet_ntoa(addr_remote.sin_addr)); 
		}

		/* Child process */
		fork_id = fork();
		if(fork_id<0)
		{
			printf("create fork error!\n");
		}
		if(fork_id==0)                    
		{  
			process(nsockfd, &addr_remote);			
		}
		else
		{
			//while(waitpid(-1, NULL, WNOHANG) > 0);
			do
			{
				pr=waitpid(fork_id, NULL, WNOHANG);
				if(pr==0){
					//printf("No child exited\n");
					sleep(1);
				}
			}
			while(pr==0);
			if(pr==fork_id)
			{
				close(nsockfd); 
				printf("child process end, successfully get child %d\n", pr);
			}
			else
				printf("some error occured\n");
		}
	}    
}

